package com.lanhai.zhonglai.impl;

import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.stereotype.Service;

import com.google.gson.Gson;
import com.lanhai.zhonglai.beans.AgvBean;
import com.lanhai.zhonglai.beans.AgvDataBean;
import com.lanhai.zhonglai.dao.AgvDao;
import com.lanhai.zhonglai.dispatch.AgvCmdMap;
import com.lanhai.zhonglai.enums.AgvCurrentTransEnum;
import com.lanhai.zhonglai.enums.AgvMountTypeEnum;
import com.lanhai.zhonglai.enums.AgvReceiveEnum;
import com.lanhai.zhonglai.interfaces.IAgv;
import com.lanhai.zhonglai.interfaces.IAgvMount;
import com.lanhai.zhonglai.interfaces.IControlArea;
import com.lanhai.zhonglai.interfaces.IPower;
import com.lanhai.zhonglai.mapper.AgvMapper;
import com.lanhai.zhonglai.mapper.StationMapper;
import com.lanhai.zhonglai.utils.Tools;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

/**
 * agv管理
 * 
 * @author zhengwei
 *
 */ 
@Service
public class AgvImpl implements IAgv {
	@Autowired
	JedisPool jedisPool;

	@Autowired
	AgvMapper agvMapper;
	@Autowired
	StationMapper stationMapper;

	@Autowired
	IPower iPower;

	@Autowired
	IAgvMount iAgvMount;

	@Autowired
	IControlArea iArea;

	@Autowired
	AgvCmdMap agvCmdMap;

	// 缓存，减少从redis中拿数据的可能性
	static Map<Integer, AgvBean> agvMap = new ConcurrentHashMap<Integer, AgvBean>();

	private static final Logger agvlog = LogManager.getLogger("agvlog");

	@Override
	public AgvBean getBean(int agvid) {
		if (agvid == 0) { 
			return null;
		}
		AgvBean tmp = agvMap.get(agvid);
		if (tmp == null) {
			// 从redis中拿
			String key = String.format("agvbean_%d", agvid);
			Jedis jd = jedisPool.getResource();
			String json = jd.get(key);
			Gson gson = new Gson();

			if (json != null && json.isEmpty() == false) {
				try {
					tmp = gson.fromJson(json, AgvBean.class);
				} catch (Exception e) {
					agvlog.error(e);
				}
			}
			if (tmp == null) {
				AgvDao dao = agvMapper.getObj(agvid);
				if (dao != null) {
					tmp = new AgvBean();
					tmp.setAgvId(agvid);
					tmp.setCurrentTrans(AgvCurrentTransEnum.None);
					tmp.setIp(dao.getIp());
					tmp.setPort(dao.getPort());
					json = gson.toJson(tmp);
					// 保存tmp
					jd.set(key, json);
					agvMap.put(agvid, tmp);
				}
			} else {
				agvMap.put(agvid, tmp);
			}
			jd.close();
		}
		if (tmp == null) {
			agvlog.error("找不到agvid=" + agvid + " 的设备");
			return null;
		}
		return tmp.copy();
	}

	@Override
	public void saveCache(AgvBean bean) {
		AgvBean old = getBean(bean.getAgvId());
		agvMap.put(bean.getAgvId(), bean);

		// 核心属性不同，才写redis
		if (notTheSame(old, bean)) {
			saveToRedis(bean);
		}
	}

	/**
	 * 判断核心属性是否不同
	 * 
	 * @param o1
	 * @param o2
	 * @return
	 */
	boolean notTheSame(AgvBean o1, AgvBean o2) {
		if (o1 == null)
			return true;
		if (o1.getDotno() != o2.getDotno())
			return true;
		if (o1.getAgvId() != o2.getAgvId())
			return true;
		if (o1.getAreaId() != o2.getAreaId())
			return true;
		if (o1.getCurrentTrans() != o2.getCurrentTrans())
			return true;
		 
		if(o1.isBothTrans()!=o2.isBothTrans()) {
			return true;
		}
		if(o1.isFakeLeave()!=o2.isFakeLeave()) {
			return true;
		}
		if(o1.isNotClear()!=o2.isNotClear()) {
			return true;
		}
		if(o1.isTransing()!=o2.isTransing()) {
			return true;
		}
		 if(o1.isToHC()!=o2.isToHC()) {
			 return true;
		 }
		 if(o1.getNextStationID()!=o2.getNextStationID()) {
			 return true;
		 }
	 
		 if(o1.isFromHC()!=o2.isFromHC()) {
			 return true;
		 }

		if (o1.getSpecialline() != o2.getSpecialline())
			return true;
		if (o1.isFinishTrans() != o2.isFinishTrans())
			return true;
		if (o1.isUpHasTrans() != o2.isUpHasTrans())
			return true;
		if (o1.isDownHasTrans() != o2.isDownHasTrans())
			return true;
		 
		if (o1.getApplyTransType() != o2.getApplyTransType())
			return true;
		if (o1.getNexttStationName() != null && o2.getNexttStationName() != null
				&& o1.getNexttStationName().equals(o2.getNexttStationName()) == false)
			return true;
		if (o1.getNextProcess() != null && o2.getNextProcess() != null
				&& o1.getNextProcess().equals(o2.getNextProcess()) == false)
			return true;
		if(o2.getLastSaveDot()!=o1.getLastSaveDot()) {
			return true;
		}
		 
		return false;
	}

	@Override
	public AgvDataBean analyseData(byte[] data) {
		if (data.length < 14) {
			return null;
		}
		if (data[0] != -95) {
			return null;
		}
		// A1 0E 02 00 00 01 F2 0D 05 02 00 64 1C 00 00
		AgvDataBean obj = new AgvDataBean();
		obj.setAgvId(data[1]);
		obj.setCmdStr(Tools.byte2HexStr(data));
		if (data[10] == 1) {
			// 小车异常
			obj.setReceiveType(AgvReceiveEnum.ERR);
			return obj;
		}
		obj.setReceiveType(AgvReceiveEnum.getAgvReceiveEnumByCode(data[2]));
		byte[] tmp = new byte[] { data[3], data[4], 0, 0 };
		obj.setRoad(Tools.toIntL(tmp));

		byte[] lb = Tools.getBooleanArray(data[12]);
		byte upleft = lb[0];
		byte upright = lb[2];
		byte downleft = lb[4];
		byte downright = lb[6];
		if (upleft > 0 && upright > 0 && downleft > 0 && downright > 0) {
			// 全满
			obj.setUpFull(true);
			obj.setDownFull(true);
			obj.setMountType(AgvMountTypeEnum.AllFull); 
		} else if (upleft == 0 && upright == 0 && downleft == 0 && downright == 0) {
			// 全空
			obj.setUpFull(false);
			obj.setDownFull(false);
			obj.setMountType(AgvMountTypeEnum.AllEmpty); 
		} else if (upleft > 0 && upright > 0 && downleft == 0 && downright == 0) {
			// 上满下空
			obj.setUpFull(true);
			obj.setDownFull(false);
			obj.setMountType(AgvMountTypeEnum.UpFullAndDownEmpty);
		} else if (upleft == 0 && upright == 0 && downleft > 0 && downright > 0) {
			// 上空下满
			obj.setUpFull(false);
			obj.setDownFull(true);
			obj.setMountType(AgvMountTypeEnum.UpEmptyAndDownFull); 
		} else {
			// 异常
			obj.setMountType(AgvMountTypeEnum.Error); 
		}
 
		obj.setPower(data[11]);

		byte[] gpX = { data[6], data[7], 0, 0 };
		byte[] gpY = { data[8], data[9], 0, 0 };
		obj.setX(Tools.toIntL(gpX));
		obj.setY(Tools.toIntL(gpY));

		obj.setData(data);
		return obj;
	}

	@Override
	public void reset(int agvid) {
		AgvBean tmp = agvMap.get(agvid);
		if (tmp != null) {
			tmp.setFinishTrans(false);
			tmp.setUpHasTrans(false);
			tmp.setDownHasTrans(false); 
			tmp.setLastCmd("");
			tmp.setCmdtime(0);
			tmp.setTransing(false); 

			saveToRedis(tmp);
		}

	}

	@Override
	public int getAgvCount(String process) {
		int sum = 0;
		for (Entry<Integer, AgvBean> entry : agvMap.entrySet()) {
			if (entry.getValue().getNextProcess().equals(process)) {
				sum++;
			}
		}
		return sum;
	}

 
	void saveToRedis(AgvBean tmp) {
		String key = String.format("agvbean_%d", tmp.getAgvId());
		Gson gson = new Gson();
		String json = gson.toJson(tmp);
		Jedis jd = jedisPool.getResource();
		jd.set(key, json);
		jd.close();
	}

}
